#ifndef __NEZHA_ENGINE_H__
#define __NEZHA_ENGINE_H__

#pragma once

#include "EngineConfig.h"
#include "SubsystemAdaptor.h"
#include "Common/EngineEvent.h"

namespace Nezha
{
	class Camera;
	class Renderer;
	class SceneGraph;
	
	namespace stream
	{
		class IFileSystem;
	}

	class NEZHA_ENGINE_ENTRY NezhaEngine : public SingletonEx<NezhaEngine>
	{
		NEZHA_SINGLETON_DECLARE(NezhaEngine)
	public:
		NezhaEngine();
		virtual ~NezhaEngine();

		/**
		@remarks
			Plugins can be two types : from dll on disk or created manually.
			For the 1st kind of plugin, specify plugin name in EngineConfig.
			For the 2nd, create and insert into adaptors.
		*/
		bool initialize(const EngineConfig& cfg, const PArray<SubsystemAdaptor*>& adaptors);

		/**
		@return
			Is engine running.
		*/
		bool update();

		void uninitialize();

		const EngineConfig& getConfig() const;

		float getFrameDelta() const;

		const char* getSubsystemModuleName(Subsystems ty) const;

		UserDataPtr getPlatformVar(const _string& name);

		void notifySystemQuitEvent();

		// TODO for debug, interface to access global variables

		typedef PMap<_string, UserDataPtr, _NzStrLess> UserDataMap;

		void addUserData(const _string& name, UserDataPtr data);
		UserDataPtr getUserData(const _string& name);
		UserDataPtr removeUserData(const _string& name);
		
NEZHA_INTERNAL:


		// for sub-system create native window.
		NZ_NativeWindow _createNativeWindow(const EngineConfig& cfg);

		void _destroyNativeWindow();

		// hidden
		UserDataPtr _getInternalInterface(const _string& name);

	protected:
		SubsystemAdaptor* mSubsys[SYS_NUM];

		SystemEventQueue* mSystemEventQueue;

		UserDataMap mUserDatas;

		Renderer* mRenderer;
		SceneGraph* mSceneGraph;

		float mFrameDelta;
		float mLastFrameTime;

#ifdef NEZHA_PROFILER_SUPPORT

		ProfileSystem* msProfileSystem;

#endif

		stream::IFileSystem* mDefFileSystem;

	private:
		EngineConfig mEngineConfig;
		DynamicLibary* mPlugins[SYS_NUM];
		bool mRunning;
	};


	inline const EngineConfig& NezhaEngine::getConfig() const
	{
		return mEngineConfig;
	}

	inline float NezhaEngine::getFrameDelta() const
	{
		return mFrameDelta;
	}


}//end namespace Nezha

#endif //end __NEZHA_ENGINE_H__